home *** CD-ROM | disk | FTP | other *** search
- /*
- * $RCSfile: analyzeCheckpoint.c,v $
- * $Revision: 1.1.1.1 $
- * $Date: 1996/05/04 21:55:55 $
- */
- /**********************************************************************
- * EXODUS Database Toolkit Software
- * Copyright (c) 1991 Computer Sciences Department, University of
- * Wisconsin -- Madison
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
- * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
- * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
- * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * The EXODUS Project Group requests users of this software to return
- * any improvements or extensions that they make to:
- *
- * EXODUS Project Group
- * c/o David J. DeWitt and Michael J. Carey
- * Computer Sciences Department
- * University of Wisconsin -- Madison
- * Madison, WI 53706
- *
- * or exodus@cs.wisc.edu
- *
- * In addition, the EXODUS Project Group requests that users grant the
- * Computer Sciences Department rights to redistribute these changes.
- **********************************************************************/
-
- #include "sysdefs.h"
- #include "ess.h"
- #include "checking.h"
- #include "trace.h"
- #include "error.h"
- #include "list.h"
- #include "pool.h"
- #include "tid.h"
- #include "io.h"
- #include "lock.h"
- #include "object.h"
- #include "msgdefs.h"
- #include "thread.h"
- #include "semaphore.h"
- #include "latch.h"
- #include "link.h"
- #include "lsn.h"
- #include "bf.h"
- #include "volume.h"
- #include "openlog.h"
- #include "trans.h"
- #include "logrecs.h"
- #include "logaction.h"
- #include "util_funcs.h"
- #include "log_intfuncs.h"
- #include "log_extfuncs.h"
- #include "recover_intfuncs.h"
- #include "recover_extfuncs.h"
- #include "trans_extfuncs.h"
- #include "thread_globals.h"
- #include "trans_globals.h"
- #include "log_globals.h"
- #include "io_globals.h"
- #include "bf_globals.h"
- #include "recover_globals.h"
- #include "distr.h"
- #include "distr_globals.h"
-
- /*
- * counter of number a dirty page table entries received from
- * LOG_ACTION_CKPNT_DIRTY_PAGES records.
- */
- static int checkPointDPTCount;
-
-
- void
- analyzeCheckpoint (
-
- register LOGRECORDHDR *record,
- register LSNOFFSET recordLSN
- )
- {
-
- register CHECKPOINTINFO *checkInfo;
- register CHECKTRANS *checkTrans;
- register TRANSREC *transRec;
- register int i;
- register DIRTYPAGEINFO *tempDirty;
- register DIRTYPAGEINFO *currentDirty;
- VOLIDNAME *mountedVolume;
- CHECKPOINTDPTINFO *dirtyPageInfoRecord;
-
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("recordLSN:%d", recordLSN));
-
- /*
- * If checkpoint record has already been anaylzed, then
- * do not analyze any more. It is possible to not start
- * at the very latest checkpoint record because the record
- * may be written, but the log volume's checkpoint info
- * may not have made it to disk. This is ok, since starting
- * at any checkpoint is correct.
- */
- if (AnalyzedCheckpoint == TRUE) {
-
- TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2, ("not last checkPoint"));
- return;
- }
-
- /*
- * check to make sure the magics are ok
- */
- SM_ASSERT(LEVEL_2, record->magic == LOGRECORD_MAGIC);
-
- /*
- * If this is a DirtyPageTable record, update the dirty
- * page table.
- */
- if (record->action == LOG_ACTION_CKPNT_DIRTY_PAGES) {
- TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2, ("checkpnt DPT record"));
-
- dirtyPageInfoRecord = (CHECKPOINTDPTINFO *) GET_LOG_IMAGE(record, 0);
-
- /* see if this is the first DPT record */
- if (dirtyPageInfoRecord->recordNum == 0) {
- checkPointDPTCount = dirtyPageInfoRecord->numDirtyPages;
- } else {
- checkPointDPTCount += dirtyPageInfoRecord->numDirtyPages;
- }
-
- /*
- * get a pointer to the dirty page information
- */
- currentDirty = (DIRTYPAGEINFO *) GET_LOG_IMAGE(record, 1);
-
- /*
- * process the list of dirty pages
- */
- for (i = 0; i < dirtyPageInfoRecord->numDirtyPages; i++, currentDirty++) {
-
- TRACE(TR_LOG|TR_RECOVER, TR_LEVEL_2);
- #ifdef DEBUG
- SM_ASSERT(LEVEL_3, currentDirty->lrc.count < OpenLog.fileBytes + 1000);
- SM_ASSERT(LEVEL_3, currentDirty->lrc.wrapCount <= OpenLog.wrapCount);
- SM_ASSERT(LEVEL_3, currentDirty->lsn.wrapCount <= OpenLog.wrapCount);
- SM_ASSERT(LEVEL_3, currentDirty->lsn.offset < OpenLog.fileBytes);
- #endif DEBUG
-
- /*
- * check to see if there is a dirty page record
- */
- if ((tempDirty = searchDirtyPageTable( &(currentDirty->pid) )) == NULL) {
-
- TRPRINT(TR_RECOVER, TR_LEVEL_2, ("pid not found"));
-
- /*
- * Add the page to the dirty page table
- */
- if ((tempDirty = insertDirtyPageTable(&(currentDirty->pid))) == NULL) {
-
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
-
- /*
- * fill in the information
- */
- tempDirty->lsn = currentDirty->lsn;
- tempDirty->lrc = currentDirty->lrc;
- TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2, ("lsn:%d, lrc:%d", tempDirty->lsn.offset, tempDirty->lrc.count));
-
- } else {
-
- /*
- * The page should not already be in the table,
- * unless more than one checkpoint record is scanned.
- */
- SM_ERROR(TYPE_LOG, esmINTERNAL);
- }
- }
-
- return;
- }
-
- /*
- * get a pointer to the body
- */
- checkInfo = (CHECKPOINTINFO *) GET_LOG_IMAGE(record, 0);
-
- #ifdef DEBUG
- {
- int x = (int) checkInfo->numActiveTrans;
- /*
- * check to make sure the active transactions are ok
- */
- SM_ASSERT(LEVEL_2, (x >= 0));
- }
- #endif DEBUG
-
- /*
- * Make sure all dirty page table information was recieved
- */
- SM_ASSERT(LEVEL_2, checkPointDPTCount == checkInfo->numDirtyPages);
-
- /*
- * Check to see if there are any active transactions
- *
- * There can be no active if this is the initial checkpoint
- */
- if (checkInfo->numActiveTrans > 0) {
-
- TRPRINT(TR_RECOVER, TR_LEVEL_2, ("numActiveTrans:%d", checkInfo->numActiveTrans));
-
- /*
- * get a pointer to the transaction information
- */
- checkTrans = (CHECKTRANS *) GET_LOG_IMAGE(record, 1);
-
- /*
- * process the active transactions
- */
- for (i = 0; i < checkInfo->numActiveTrans; i++, checkTrans++) {
-
- TRACE(TR_LOG|TR_RECOVER, TR_LEVEL_2);
-
- /*
- * add the trans to the active list only if it really was
- * active at the time of the checkpoint. An example of one
- * that is NOT active is one that was commited but whose
- * resources had not yet been released at the time the
- * checkpoint was taken
- */
-
- if (TRANS_NOT_ALIVE_AT_CHECKPOINT(checkTrans))
- continue;
-
-
- /*
- * check to see if there is a transaction record
- */
- if ((transRec = findTransRec(checkTrans->tid)) == NULL) {
-
- TRPRINT(TR_RECOVER, TR_LEVEL_2, ("tid not found"));
-
- /*
- * allocate a transaction record
- */
- if ((transRec = allocRecoveryTrans()) == NULL) {
-
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
-
- /*
- * hang the transaction off the hash table
- */
- listPush( &(TransHashTable[HASH_TID(checkTrans->tid)]), &(transRec->tidList) );
-
- /*
- * fill in the transaction information
- */
- transRec->tid = checkTrans->tid;
- transRec->firstLSN = checkTrans->firstLSN;
- transRec->lastLSN = checkTrans->lastLSN;
- transRec->nextUndoLSN = checkTrans->nextUndoLSN;
-
- /*
- * for distr trans
- */
- transRec->transState = checkTrans->state;
- transRec->numServers = checkTrans->numServers;
- transRec->prepareLSN = checkTrans->prepareLSN;
-
- if (transRec->transState == T_ACTIVE) {
- /*
- * change the state to T_RECOVER since that
- * corresponds to T_ACTIVE in the checkpoint
- */
- transRec->transState = T_RECOVER;
- }
-
- /*
- * see if the transaction is a distr trans
- */
- if ((transRec->transState == T_PREPARED) &&
- (transRec->numServers == 0)) {
-
- /*
- * add this transRec to list of distr trans
- * for which this server is a participant
- */
- listEnq( &(ServerDistrTransList), &(transRec->distrTransList) );
- /*
- * increment the number of active distr trans
- * for which this server is a participant
- */
- numActiveServerDistrTrans++;
- }
- else if (((transRec->transState == T_PREPARED) ||
- (transRec->transState == T_COMMIT)) &&
- (transRec->numServers > 0)) {
-
- /*
- * add this transRec to list of distr trans
- * for which this server is the coordinator
- */
- listEnq( &(CoordDistrTransList), &(transRec->distrTransList) );
- /*
- * increment the number of active distr trans
- * for which this server is the coordinator
- */
- numActiveCoordDistrTrans++;
-
- }
-
- TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2,
- ("firstLSN:%d lastLSN:%d", transRec->firstLSN.offset, transRec->lastLSN));
- }
- }
- }
-
- /*
- * check the validity of the checkpoint info
- * make sure dirty page table is empty (ie. list is empty)
- */
- SM_ASSERT(LEVEL_2, checkInfo->numDirtyPages >= 0);
-
- TRPRINT(TR_RECOVER, TR_LEVEL_2, ("numDirtyPages:%d", checkInfo->numDirtyPages));
-
- /*
- * Check to see if there are any mounted volumes
- * There can be no active if this is the initial checkpoint
- */
- CheckpointVolumeCount = checkInfo->mountedVolCount;
- if (checkInfo->mountedVolCount > 0) {
-
- /*
- * get a pointer to the mounted volume information
- */
- mountedVolume = (VOLIDNAME *) GET_LOG_IMAGE(record, 2);
-
- if (checkInfo->mountedVolCount > NumVolumes) {
- fprintf(sm_ErrorStream,
- "The server's configuration at recovery must match");
- fprintf(sm_ErrorStream,
- " its configuration at the time of the crash.\n");
- fprintf(sm_ErrorStream,
- "At the time of the crash, %d volumes were mounted\n",
- checkInfo->mountedVolCount);
- fprintf(sm_ErrorStream,
- "The configuration now mounts only %d volumes\n", NumVolumes);
- SM_ERROR(TYPE_STOP, esmCANNOTRECOVER);
- }
-
- /*
- * process the list of mounted volumes
- */
- for (i = 0; i < checkInfo->mountedVolCount; i++, mountedVolume++) {
-
- /*
- * Add the volume to the checkpoint mounted volume list
- */
- CheckpointVolumes[i] = *mountedVolume;
- }
- }
-
-
- /* we have completed analysis of the checkpoint record */
- AnalyzedCheckpoint = TRUE;
-
- }
-